home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #2
/
Monster Media No. 2 (Monster Media)(1994).ISO
/
prog_gen
/
guslib.zip
/
GUSLIB.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-08-26
|
23KB
|
979 lines
ideal
model large ; Replace this w/ whatever model your using
p286 ; This code was written for 286+ machines
jumps ; Allows far conditional jumps in 286 code
assume ds:gus_data,cs:gus
public guslib
; Our variables are stored in our own segment for portability...
segment gus_data private
gus_string db 'ULTRASND=',0
base_port dw ?
gf1_page dw ?
gf1_register dw ?
gf1_data_low dw ?
gf1_data_high dw ?
irq_status dw ?
timer_control dw ?
timer_data dw ?
dram dw ?
mixer dw ?
irq_dma_control dw ?
register_controls dw ?
mixer_controls dw ?
play_back_dma db ?
play_back_dma_mask db ?
gf1_irq db ?
gf1_irq_mask db ?
midi_irq db ?
midi_irq_mask db ?
irq_control db 8,15,12,11,7,3,5,2,0
dma_control db 6,7,6,5,3,1,0
dma_channels db 7 dup (00h)
db 0ah,0ch,02h,03h,0bh,83h,0ah
db 7 dup (00h)
db 0ah,0ch,06h,07h,0bh,82h,0ah
db 7 dup (00h)
db 0d4h,0d8h,0c4h,0c6h,0d6h,8bh,0d4h
db 0d4h,0d8h,0c8h,0cah,0d6h,89h,0d4h
db 0d4h,0d8h,0cch,0ceh,0d6h,8ah,0d4h
initialization db ?
voice db 00h
max_voices db 14h
divisor dw 0000h
d1 db ?
d2 db ?
old_ISR1 dd ?
old_ISR2 dd ?
old_flags dw ?
irq_source db ?
irq_voice db ?
old_voice db ?
dma_send dw 0000h
dma_pos_high db 00h
dma_pos_low dw 0000h
dma_size_high db 00h
dma_size_low dw 0000h
dma_busy db 00h
dma_wait db 00h
dram_addr dw 0000h
gus_functions dw offset init_gus
dw offset deinit_gus
dw offset poke
dw offset peek
dw offset set_active
dw offset download_sound
dw offset dma_status
dw offset set_volume
dw offset set_freq
dw offset set_loop
dw offset set_start
dw offset set_end
dw offset play_voice
dw offset voice_status
dw offset stop_voice
dw offset read_8bit_reg
dw offset write_8bit_reg
dw offset read_16bit_reg
dw offset write_16bit_reg
lc db '0'
pos dw 3840
ends gus_data
segment gus public
proc value16 near
push ax bx di es
mov bx,0b800h
mov es,bx
mov al,[lc]
mov di,[pos]
mov [es:di],al
inc [lc]
cmp [lc],'9'+1
jnz nu
mov [lc],'0'
nu: add [pos],2
cmp [pos],4000
jnz nu2
mov [pos],3840
nu2: pop es di bx ax
ret
endp value16
proc guslib far
cmp bx,12h
jnc No_Func
push ds
push ax
mov ax,gus_data
mov ds,ax
pop ax
shl bx,1
add bx,offset gus_functions
call [word ptr ds:bx]
pop ds
No_Func: ret
endp guslib
proc delay near
push cx dx ax
mov cx,7
mov dx,[base_port]
d_lp1: in al,dx
loop d_lp1
pop ax dx cx
ret
endp delay
proc read_8bit_reg near
push dx
pushf
cli
mov dx,[gf1_register]
cmp al,0fh
jnc no_spc
add al,80h
no_spc: out dx,al
add dx,2
in al,dx
popf
pop dx
ret
endp read_8bit_reg
proc read_16bit_reg near
push dx
pushf
cli
mov dx,[gf1_register]
cmp al,0fh
jnc no_spc2
add al,80h
no_spc2: out dx,al
inc dx
in ax,dx
popf
pop dx
ret
endp read_16bit_reg
proc write_8bit_reg near
push dx
push ax
pushf
cli
mov dx,[gf1_register]
out dx,al
add dx,2
mov al,ah
out dx,al
call delay
out dx,al
popf
pop ax
pop dx
ret
endp write_8bit_reg
proc write_16bit_reg near
push dx
push ax
pushf
cli
mov dx,[gf1_register]
out dx,al
inc dx
mov ax,cx
out dx,ax
call delay
out dx,ax
popf
pop ax
pop dx
ret
endp write_16bit_reg
proc poke near ; si=high di=low al=value
pushf
push dx
push ax
cli
mov dx,[gf1_register]
mov al,43h
out dx,al
inc dx
mov ax,di
out dx,ax
dec dx
mov al,44h
out dx,al
inc dx
inc dx
mov ax,si
out dx,al
add dx,2
pop ax
out dx,al
call delay
out dx,al
pop dx
popf
ret
endp poke
proc peek near ; ah=voice si=high di=low al=return value
push dx
mov dx,[gf1_register]
mov al,43h
out dx,al
inc dx
mov ax,di
out dx,ax
dec dx
mov al,44h
out dx,al
inc dx
mov ax,si
out dx,al
add dx,3
xor ax,ax
in al,dx
pop dx
ret
endp peek
proc init_gus near
mov [initialization],00h ; Don't need to deinit yet
push es
mov ah,51h ; Get the current PSP segment
int 21h
mov es,bx
mov ax,[es:002ch] ; Find the environment strings
mov es,ax
mov si,offset gus_string
mov di,0 ; Find the 'ULTRASND=' string
env_lp1: mov al,[es:di]
inc di
cmp al,0
jnz env_lp2
mov al,[es:di+1]
cmp al,0
jz env_err
rst_env: mov si,offset gus_string
jmp env_lp1
env_lp2: mov ah,[si]
cmp ah,0
jz env_ok
cmp al,ah
jnz rst_env
inc si
jmp env_lp1
env_err: mov ax,1 ; String not found - Return code 1
jmp init_done
env_ok: xor ax,ax ; Found string - Process variable
mov al,[es:di]
sub al,'0'
rol ax,4
add ax,200h
mov [base_port],ax ; Base Port (2x0h)
add di,3
mov al,[es:di]
sub al,'0'
mov [play_back_dma],al ; Play back DMA Channel
add di,4
mov al,[es:di]
sub al,'0'
mov [gf1_irq],al ; GF1 (Channel 1) Irq
add di,2
mov al,[es:di]
sub al,'0'
mov [midi_irq],al ; MIDI (Channel 2) Irq
mov bx,[base_port] ; Set up I/O port address
mov [mixer],bx ; Mix Control Register (2x0h)
add bx,0bh
mov [irq_dma_control],bx ; IRQ/DMA Control Register
add bx,04h
mov [register_controls],bx ; Register Controls
add bx,0f3h
mov [gf1_page],bx ; GF1 Page Selector
inc bx
mov [gf1_register],bx ; GF1/Global Register Selector
inc bx
mov [gf1_data_low],bx ; GF1/Global Data Low Byte
inc bx
mov [gf1_data_high],bx ; GF1/Global Data High Byte
inc bx
mov [mixer_controls],bx ; Mixer Conrols
sub bx,100h
mov [irq_status],bx ; Irq Status Register
add bx,2
mov [timer_control],bx ; Timer Control Register
inc bx
mov [timer_data],bx ; Timer Data
add bx,0feh
mov [dram],bx ; Direct DRAM I/O Register
; Environmental Variables are loaded... Procede w/ reseting the GUS
mov ax,064ch ; Write 06h to Reset port (4ch)
call write_8bit_reg
mov ax,074ch ; Done w/ reset, now write 07h
call write_8bit_reg
mov al,4ch ; Read the reset port
call read_8bit_reg
mov bl,al
mov ax,4 ; If it isn't 07h, then we've
cmp bl,07h ; got a problem...
jnz init_done
; Now, make sure the on board memory is there. This ensures that
; we acually have an ultrasound.
mov al,33h
mov si,0
mov di,0
call poke
mov al,55h
mov di,2
call poke
mov di,0
call peek
cmp al,33h
jnz bad_dram
mov di,2
call peek
cmp al,55h
jnz bad_dram
; Now set up the on-board IRQs...
mov dx,[mixer]
mov al,4fh
out dx,al
xor cx,cx
mov cl,[byte irq_control]
mov si,1
mov ah,[gf1_irq]
rst_lp1: mov al,[byte irq_control+si]
cmp ah,al
jz rst_dn1
inc si
loop rst_lp1
jmp bad_irq
rst_dn1: dec cx
mov [gf1_irq_mask],cl
xor cx,cx
mov cl,[byte irq_control]
mov si,1
mov ah,[midi_irq]
rst_lp2: mov al,[byte irq_control+si]
cmp ah,al
jz rst_dn2
inc si
loop rst_lp2
jmp bad_irq
rst_dn2: dec cx
mov [midi_irq_mask],cl
mov dx,[irq_dma_control]
mov bl,0
mov al,[gf1_irq_mask]
mov ah,[midi_irq_mask]
cmp ah,al
jnz ct_msk1
mov ah,0
mov bl,40h
ct_msk1: rol ah,3
or al,ah
or al,bl
out dx,al
mov dx,[mixer]
mov al,0fh
out dx,al
xor cx,cx
mov cl,[byte dma_control]
mov si,1
mov ah,[play_back_dma]
rst_lp3: mov al,[byte dma_control+si]
cmp ah,al
jz rst_dn3
inc si
loop rst_lp3
jmp bad_dma
rst_dn3: dec cx
mov al,40h
or al,cl
mov dx,[irq_dma_control]
out dx,al
mov al,[play_back_dma]
and al,3
mov [play_back_dma_mask],al
; Set up IRQs and ISRs. From this point, deinitialization is a MUST!
pushf
cli
mov ah,35h
mov al,[gf1_irq]
add al,8
int 21h
mov [word old_ISR1],bx
mov [word old_ISR1+2],es
mov ah,35h
mov al,[midi_irq]
add al,8
int 21h
mov [word old_ISR2],bx
mov [word old_ISR2+2],es
mov ah,25h
mov al,[gf1_irq]
add al,8
push ds
mov dx,offset gf1_ISR
mov bx,seg gf1_ISR
mov ds,bx
int 21h
pop ds
mov ah,25h
mov al,[midi_irq]
add al,8
push ds
mov dx,offset midi_ISR ; Like we're using it here?!?
mov bx,seg midi_ISR
mov ds,bx
int 21h
pop ds
in al,0a1h
mov ah,al
in al,21h
mov [old_flags],ax
mov bx,1
mov dx,1
mov cl,[gf1_irq]
shl bx,cl
mov cl,[midi_irq]
shl dx,cl
or bx,dx
not bx
and ax,bx
out 21h,al
mov al,ah
out 0a1h,al
popf
mov [initialization],01h ; We MUST deinit now...
mov dx,[mixer] ; Activate the GUS!
mov al,09h
out dx,al
mov dx,[gf1_page] ; Select voice 0
mov al,0
out dx,al
mov [voice],0
mov ax,0
jmp init_done
bad_irq: mov ax,2
jmp init_done
bad_dma: mov ax,3
jmp init_done
bad_dram: mov ax,5
jmp init_done
init_done:
pop es
ret
endp init_gus
proc deinit_gus near
pushf
cli
cmp [initialization],01h ; Did we initialize?
jnz no_init
mov ah,25h
mov al,[gf1_irq]
add al,8
push ds
lds dx,[dword old_ISR1]
int 21h
pop ds
mov ah,25h
mov al,[midi_irq]
add al,8
push ds
lds dx,[dword old_ISR2]
int 21h
pop ds
mov ax,[old_flags]
out 21h,al
mov al,ah
out 0a1h,al
no_init: mov dx,[mixer]
mov al,0bh
out dx,al
popf
ret
endp deinit_gus
proc dma_status near
xor ax,ax
mov al,[dma_busy]
ret
endp dma_status
proc midi_ISR far ; Null ISR
push ax
mov al,20h
out 20h,al
pop ax
iret
endp midi_ISR
proc set_active near
push dx
dec ax
cmp al,13
jnc nl13
mov al,13
nl13: cmp al,32
jc lt32
mov al,31
lt32: mov [max_voices],al
or al,0c0h
mov ah,al
mov al,0eh
call write_8bit_reg
xor bx,bx
mov bl,[max_voices]
inc bx
mov ax,6bb8h
mov dx,9
div bx
mov [divisor],ax
pop dx
ret
endp set_active
proc download_sound near ; es:si = source di = dram addr
; dx:ax = size cl = wait toggle
cmp [dma_busy],1
jz no_dma
mov [dma_wait],cl
mov [dma_size_high],dl
mov [dma_size_low],ax
mov [dram_addr],di
mov ax,es
rol ax,4
and ax,15
mov [dma_pos_high],al
mov ax,es
and ax,0fffh
rol ax,4
and si,0ff00h
add ax,si
mov [dma_pos_low],ax
xor ax,ax
sub ax,[dma_pos_low]
mov [dma_send],ax
cmp [dma_size_high],0
jnz gt64k
mov bx,[dma_size_low]
cmp ax,bx
jc gt64k
mov [dma_send],bx
mov [dma_size_low],0
jmp go_dma
gt64k: sub [dma_size_low],ax
sbb [dma_size_high],0
go_dma: xor ax,ax
mov al,[play_back_dma]
mov bx,7
imul bx
add ax,offset dma_channels
mov si,ax
xor dx,dx
mov dl,[si]
mov al,[play_back_dma_mask]
or al,4
out dx,al
mov al,0
mov dl,[si+1]
out dx,al
mov ax,[dma_pos_low]
mov dl,[si+2]
out dx,al
mov al,ah
out dx,al
mov ax,[dma_send]
dec ax
mov dl,[si+3]
out dx,al
mov al,ah
out dx,al
mov al,[play_back_dma_mask]
or al,48h
mov dl,[si+4]
out dx,al
mov al,[dma_pos_high]
mov dl,[si+5]
out dx,al
mov al,[play_back_dma_mask]
mov dl,[si+6]
out dx,al
pushf
cli
mov al,42h
mov cx,[dram_addr]
call write_16bit_reg
mov dx,[gf1_register]
mov al,41h
out dx,al
add dx,2
mov al,0a9h
mov [dma_busy],1
out dx,al
popf
cmp [dma_wait],0
jz dma_dn
dma_lp1: mov ah,6
mov dl,0ffh
int 21h
jnz keyht1
cmp [dma_busy],1
jz dma_lp1
mov ax,0
dma_dn: ret
keyht1: mov ax,1
jmp dma_dn
no_dma: mov ax,2
jmp dma_dn
endp download_sound
proc gf1_ISR far ; Handles ALL GF1 interrupts
push ax dx ds
mov ax,gus_data
mov ds,ax
call delay
call delay
irq_lp1: mov dx,[irq_status]
in al,dx
cmp al,0
jz gf1_dn
test al,80h
jz no_dma2
mov dx,[gf1_register]
mov al,41h
out dx,al
add dx,2
in al,dx
inc [dma_pos_high]
mov [dma_pos_low],0
cmp [dma_send],0
jnz lt64k
add [dram_addr],1000h
dec [dma_size_high]
jmp dma_go
lt64k: mov ax,[dma_send]
mov cl,4
shr ax,cl
add [dram_addr],ax
dma_go: cmp [dma_size_high],0
jz lt64k2
mov [dma_send],0
jmp dma_go2
lt64k2: cmp [dma_size_low],0
jz dma_dn2
mov ax,[dma_size_low]
mov [dma_send],ax
dma_go2: mov ax,[dma_send]
sub [dma_size_low],ax
sbb [dma_size_high],0
xor ax,ax
mov al,[play_back_dma]
mov bx,7
imul bx
add ax,offset dma_channels
mov si,ax
xor dx,dx
mov dl,[si]
mov al,[play_back_dma_mask]
or al,4
out dx,al
mov al,0
mov dl,[si+1]
out dx,al
mov ax,[dma_pos_low]
mov dl,[si+2]
out dx,al
mov al,ah
out dx,al
mov ax,[dma_send]
dec ax
mov dl,[si+3]
out dx,al
mov al,ah
out dx,al
mov al,[play_back_dma_mask]
or al,48h
mov dl,[si+4]
out dx,al
mov al,[dma_pos_high]
mov dl,[si+5]
out dx,al
mov al,[play_back_dma_mask]
mov dl,[si+6]
out dx,al
pushf
cli
mov al,42h
mov cx,[dram_addr]
call write_16bit_reg
mov dx,[gf1_register]
mov al,41h
out dx,al
add dx,2
mov al,0a9h
mov [dma_busy],1
out dx,al
popf
jmp gf1_dn
dma_dn2: mov [dma_busy],0
jmp gf1_dn
no_dma2: test al,40h ; I'm not really sure why this code
jnz no_voc ; is here, or even if it really works.
mov al,0fh ; I've never really had a need to make
call read_8bit_reg ; sure the voice has stopped at any
mov [irq_source],al ; perticular time. There's just times
and al,1fh ; when I need to know IF it's stopped.
mov [irq_voice],al ; At any rate, I never use an IRQ for
mov al,[irq_source] ; the end-of-voice, but it would come
and al,0c0h ; in nice for music, so I left the
cmp al,0c0h ; here for anyone to work with.
jz irq_lp1
test al,80h
jnz no_voc
mov al,[voice]
mov [old_voice],al
mov dx,[gf1_page]
out dx,al
mov al,0
call read_8bit_reg
mov [d1],al
mov al,0dh
call read_8bit_reg
test [d1],4
jnz virq_dn
test al,4
jnz virq_dn
mov ax,100h
call write_8bit_reg
mov al,2
call read_16bit_reg
mov cx,ax
mov al,0ah
call write_16bit_reg
mov al,3
call read_16bit_reg
mov cx,ax
mov al,0bh
call write_16bit_reg
virq_dn: mov al,[old_voice]
mov dx,[gf1_page]
out dx,al
no_voc:
gf1_dn: mov al,20h
out 20h,al
pop ds dx ax
iret
endp gf1_ISR
proc set_volume near ; ax = value (0-4095) cl = voice
push dx
push ax
mov al,cl
mov dx,[gf1_page]
out dx,al
pop ax
push cx
mov cl,4
shl ax,cl
mov cx,ax
mov al,9
call write_16bit_reg
pop cx
pop dx
ret
endp set_volume
proc set_freq near ; ax = frequency of voice (0-44100) cl = voice
push dx
push cx
push ax
mov al,cl
mov dx,[gf1_page]
out dx,al
pop ax
mov bx,512
imul bx
mov bx,[divisor]
shr bx,1
add ax,bx
adc dx,0
mov bx,[divisor]
div bx
shl ax,1
mov cx,ax
mov al,1
call write_16bit_reg
pop cx
pop dx
ret
endp set_freq
proc set_loop near ; al = loop ctrl register (recommended value = 3)
; cl = voice
push dx
push cx
mov dx,[gf1_page]
mov ah,al
mov al,cl
out dx,al
mov al,0dh
call write_8bit_reg
pop cx
pop dx
ret
endp set_loop
proc set_start near ; dx:ax cl = voice
push cx
push dx
push ax
mov dx,[gf1_page]
mov al,cl
out dx,al
pop ax
pop dx
call adjust
mov cx,ax
mov al,3
call write_16bit_reg
mov al,0bh
call write_16bit_reg
mov cx,dx
mov al,2
call write_16bit_reg
mov al,0ah
call write_16bit_reg
pop cx
ret
endp set_start
proc set_end near ; dx:ax cl = voice
push cx
push dx
push ax
mov dx,[gf1_page]
mov al,cl
out dx,al
pop ax
pop dx
call adjust
mov cx,ax
mov al,5
call write_16bit_reg
mov cx,dx
mov al,4
call write_16bit_reg
pop cx
ret
endp set_end
proc adjust near
mov cx,9
adj_lp1: clc
rcl ax,1
rcl dx,1
loop adj_lp1
ret
endp adjust
proc play_voice near ; al = voice ah = control register (00h = norm)
mov bh,ah
mov dx,[gf1_page]
out dx,al
inc dx
mov al,80h
out dx,al
add dx,2
in al,dx
test al,1
jnz voc_ok
mov ax,300h
call write_8bit_reg
mov al,2
call read_16bit_reg
mov cx,ax
mov al,0ah
call write_16bit_reg
mov al,3
call read_16bit_reg
mov cx,ax
mov al,0bh
call write_16bit_reg
voc_ok: pushf
cli
mov dx,[gf1_register]
mov al,0
out dx,al
and bh,5ch
add dx,2
mov al,bh
out dx,al ; Let the sound begin! :)
call delay
out dx,al
popf
ret
endp play_voice
proc stop_voice near ; al = voice
mov dx,[gf1_page]
out dx,al
mov ax,300h
call write_8bit_reg
mov al,2
call read_16bit_reg
mov cx,ax
mov al,0ah
call write_16bit_reg
mov al,3
call read_16bit_reg
mov cx,ax
mov al,0bh
call write_16bit_reg
ret
endp stop_voice
proc voice_status near
mov al,0h
call read_8bit_reg
mov ah,0
and al,1
ret
endp voice_status
ends gus
end